/**
 * Copyright (c) 2010-2011 Pierre Labatut
 *
 * This file is part of Space-Chronicles project.
 *
 * Space-Chronicles is free software: you can redistribute it and/or modify it
 * under the terms of its license which may be found in the accompanying
 * LICENSE file or at <http://code.google.com/p/space-cronicles/>.
 */
package space.game.world;

import com.jogamp.opengl.util.texture.Texture;
import com.jogamp.opengl.util.texture.TextureIO;
import java.io.IOException;
import java.net.URL;
import javax.media.opengl.GL2;
import javax.media.opengl.GL3bc;
import javax.media.opengl.GLException;
import jinngine.math.Matrix4;
import jinngine.math.Vector3;
import space.gl.RenderContext;
import space.gl.RenderContext.Pass;
import space.model.Drawable;

/**
 *
 * @author Pierre Labatut
 */
public class Billboard implements Drawable {

    final Texture texture;
    final float size = 10f;

    public Billboard() {
        try {
            final URL textureUrl = getClass().getResource("default.png");
            texture = TextureIO.newTexture(textureUrl, true, null);
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        } catch (GLException ex) {
            throw new RuntimeException(ex);
        }
    }

    public Drawable optimize(GL3bc gl) {
        return this;
    }

    public void draw(final RenderContext rc) {
        if (rc.pass() != Pass.SHADE) {
            return;
        }
        /*
        final Matrix4 spherical = rc.getWorldView().toMatrix3().transpose().toMatrix4(new Matrix4());
        rc.compose(spherical);
         */
        if(true)
        {
            Matrix4 vw = rc.worldView.inverse();
            Vector3 lookAt = vw.multiply(new Vector3());

            final Vector3 up = new Vector3(rc.worldView.a21, rc.worldView.a22,
                    rc.worldView.a23);

            Vector3 third = up.cross(lookAt);
            Vector3.crossProduct(lookAt, third, up);

            double lookAtNorm = lookAt.norm();
            if (lookAtNorm <= 0.) {
                return; // Degenerated case when I have a billboard in the eye   
            }
            lookAtNorm = 1. / lookAtNorm;

            up.assignNormalize();
            third.assignNormalize();

            rc.objectWorld.a11 = third.x;
            rc.objectWorld.a21 = third.y;
            rc.objectWorld.a31 = third.z;

            rc.objectWorld.a12 = up.x;
            rc.objectWorld.a22 = up.y;
            rc.objectWorld.a32 = up.z;

            rc.objectWorld.a13 = lookAt.x * lookAtNorm;
            rc.objectWorld.a23 = lookAt.y * lookAtNorm;
            rc.objectWorld.a33 = lookAt.z * lookAtNorm;
        }
        
        if (false) {
            /**
             * Cylindrical billboard turn around their z local axis to face the viewpoint
             * This is the vertical direction: y of image
             */
            final Vector3 pivot = new Vector3(rc.objectWorld.a13, rc.objectWorld.a23,
                    rc.objectWorld.a33);
            /**
             * Cylindrical billboard plane is perpendicular to the viewpoint         
             */
            final Matrix4 vw = rc.worldView.inverse();
            Vector3 lookAt = vw.multiply(new Vector3());
            Vector3 third = pivot.cross(lookAt);

            double pivotNorm = pivot.norm();
            if (pivotNorm <= 0.) {
                throw new IllegalArgumentException("The objectWorld matric is degenrated");
            }
            pivotNorm = 1. / pivotNorm;

            double lookAtNorm = lookAt.norm();
            if (lookAtNorm <= 0.) {
                return; // Degenerated case when I have a billboard in the eye   
            }
            lookAtNorm = 1. / lookAtNorm;

            double thirdNorm = third.norm();
            if (thirdNorm <= 0.) {
                return; // Degenerated case when I look in the ba direction
            }
            thirdNorm = 1. / thirdNorm;

            rc.objectWorld.a11 = third.x * thirdNorm;
            rc.objectWorld.a21 = third.y * thirdNorm;
            rc.objectWorld.a31 = third.z * thirdNorm;

            rc.objectWorld.a12 = pivot.x * pivotNorm;
            rc.objectWorld.a22 = pivot.y * pivotNorm;
            rc.objectWorld.a32 = pivot.z * pivotNorm;

            rc.objectWorld.a13 = lookAt.x * lookAtNorm;
            rc.objectWorld.a23 = lookAt.y * lookAtNorm;
            rc.objectWorld.a33 = lookAt.z * lookAtNorm;

        }


        rc.stopUsingProgram();
        rc.applyLegacyMatrix();

        GL3bc gl = rc.gl();

        gl.glDisable(GL2.GL_TEXTURE_2D);
        gl.glActiveTexture(GL2.GL_TEXTURE1);
        gl.glDisable(GL2.GL_TEXTURE_2D);
        gl.glActiveTexture(GL2.GL_TEXTURE2);
        gl.glDisable(GL2.GL_TEXTURE_2D);
        gl.glActiveTexture(GL3bc.GL_TEXTURE0);
        gl.glEnable(gl.GL_TEXTURE_2D);

        gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL);
        gl.glTexEnvi(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_REPLACE);

        gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR);
        gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST);
        gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE);
        gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE);
        texture.bind();
        gl.glBegin(GL3bc.GL_QUADS);
        gl.glTexCoord2f(0.f, 0.f);
        gl.glVertex2f(-size, +size);
        gl.glTexCoord2f(0.f, 1.f);
        gl.glVertex2f(+size, +size);
        gl.glTexCoord2f(1.f, 1.f);
        gl.glVertex2f(+size, -size);
        gl.glTexCoord2f(1.f, 0.f);
        gl.glVertex2f(-size, -size);
        gl.glEnd();

        rc.startUsingProgram();
    }

    public void dispose(GL3bc rc) {
    }
}
